﻿using System;
using System.Collections.Generic;
using System.Linq;
using SapaFinance.Domain.Extensions;

namespace SapaFinance.Domain.Model
{
    public class Request : AbstractEntity
    {
        //can use protected for EF4.1 and NHibernate, not private. In this case relaited property will be load in virtual property (lazy load=true)!!!
        protected Request() {}

        public Request(User user)
            : this()
        {
            CreatedBy = new Identity(user);
            Change(user);
            PartialPayment = new HashSet<Share>();
        }

        //[DisplayName("Получатель в кассе")]
        //public virtual User PayeeCashUser { get; private set; }
        public virtual PaymentType PaymentType { get; private set; }
        public virtual Corporation Payer { get; private set; }
        public virtual Corporation Payee { get; private set; }
        public virtual Account PayeeAccount { get; private set; }
        public virtual DateTime PaymentPeriod { get; set; }
        public virtual Money Payment { get; private set; }
        public virtual TaxRate TaxRate { get; private set; }
        public virtual string PaymentPurpose { get; set; }
        public virtual BudgetItem BudgetItem { get; private set; }
        public virtual int Unique { get; set; }
        public virtual Identity CreatedBy { get; private set; }
        public virtual Identity ChangedBy { get; private set; }
        public virtual Identity AcceptedBy { get; private set; }
        public virtual Identity DeletedBy { get; private set; }
        public virtual string Description { get; set; }
        public virtual CFO Department { get; private set; }
        public virtual ICollection<Share> PartialPayment { get; private set; }

        public bool IsAccepted
        {
            get { return AcceptedBy != null; }
        }

        public bool IsDeleted
        {
            get { return DeletedBy != null; }
        }

        public void Change(User user)
        {
            ChangedBy = new Identity(user);
        }

        public Money GetNotPaidAmount()
        {
            return PartialPayment.Any() ? Payment - GetPaidAmount(Payment.Currency) : Payment;
        }

        public Money GetPaidAmount(Currency currency)
        {
            if (PartialPayment.Any())
                return PartialPayment.Sum(x => x.Amount);
            return Money.Create(0, currency);
        }
        public decimal GetPaymentRatio()
        {
            return (GetPaidAmount(Payment.Currency)/Payment).Amount;
        }

        public void SetPayer(Corporation payer)
        {
            Payer = payer;
        }

        /// <summary>
        /// Указать для заявки юр. лицо получателя. Установить для заявки "основной счет" получателя по умолчанию.
        /// </summary>
        /// <param name="payee"></param>
        public void SetPayee(Corporation payee)
        {
            Payee = payee;
            if (PayeeAccountIsAbsent())
                SetPayeeAccount(payee.GetPrimaryAccount());
        }

        /// <summary>
        /// Счет получателя у заявки не установлен.
        /// </summary>
        /// <returns></returns>
        public bool PayeeAccountIsAbsent()
        {
            return PayeeAccount == null;
        }

        /// <summary>
        /// Отсутствует получатель.
        /// </summary>
        /// <returns></returns>
        public bool PayeeIsAbsent()
        {
            return Payee == null;
        }

        public void SetPaymentType(PaymentType paymentType)
        {
            PaymentType = paymentType;
        }

        /// <summary>
        /// Установить счет получателя у заявки, если получатель определен в заявке и у получателя есть такой счет.
        /// </summary>
        /// <param name="payee"></param>
        /// <param name="account"></param>
        public void SetPayeeAccount(Account account)
        {
            if (!PayeeIsAbsent()){
                if (Payee.Accounts.Contains(account))
                    PayeeAccount = account;
            }
        }

        /// <summary>
        /// Установить сумму платежа, если счет получателя определен. Тип валюты будет взят из типа валюты счета получателя.
        /// </summary>
        /// <param name="amount"></param>
        public void SetPayment(decimal amount)
        {
            if (!PayeeAccountIsAbsent())
                Payment = Money.Create(amount, PayeeAccount.Currency);
        }

        public void SetDepartment(CFO department)
        {
            Department = department;
        }

        public void SetTaxRate(int taxRate)
        {
            TaxRate = new TaxRate(taxRate);
        }

        public void SetBudgetItem(BudgetItem budgetItem)
        {
            BudgetItem = budgetItem;
        }

        //public void SetPayeeCash(User user)
        //{
        //    PayeeCashUser = user;
        //}
        public void Accept(User user)
        {
            AcceptedBy = new Identity(user);
        }

        public void Delete(User user)
        {
            DeletedBy = new Identity(user);
        }

        public void AddPartialPayment(Share partialPayment)
        {
            PartialPayment.Add(partialPayment);
        }

        //размер оплаты по распоряжению в процентах
        public int PaidPercentByOrder()
        {
            var paymentRatio = GetPaymentRatio();
            return  Convert.ToInt32(paymentRatio.RoundTo(DecimalSize.Two)*100);
            //switch (result){
            //    case 0:
            //        return 100;
            //    case 100:
            //        return 0;
            //    default:
            //        return result;
            //}
        }
    }
}